home *** CD-ROM | disk | FTP | other *** search
/ The Original Shareware 1.1 / The Original Shareware (WeMake CDs)(Volume 1.1)(CDs, Inc)(1993).iso / 16 / xmodemc.zip / XMODEM.C next >
C/C++ Source or Header  |  1986-12-17  |  9KB  |  374 lines

  1. /* xmodem.c copyright 1986 Maple Lawn Farm, Inc. 
  2.  * exit: 0 if successful, -1 for failure, compile with mlfcu.c:
  3.  *      cc -i -O -s -DCU mlfcu.c xmodem.c -o cu or with xr.c:
  4.  *      cc -i -O -s xr.c xmodem.c -o xr, ln xr xt */
  5.  
  6. #include <signal.h>
  7. #include <stdio.h>
  8.  
  9. #ifdef CU
  10.  
  11. extern int     rlfd;        /* the open line in cu */
  12. #define WFD    rlfd
  13. #define RFD    rlfd
  14. #define errf   stderr
  15.  
  16. #else
  17.  
  18. extern  FILE   *errf;       /* error file for remote */
  19. #define WFD    1            /* stdout */
  20. #define RFD    0            /* stdin */
  21.  
  22. #endif
  23.  
  24. #define BSIZE         128
  25. #define DEBUG         01
  26. #define LF            02
  27. #define CRC           04
  28. #define NOREAD(x, c)  (rchar(x, &c) == -1)
  29. #define TX(c)         write(WFD, &c, 1)  
  30. #define ever          (;;)
  31.  
  32. static  char   soh = 0x01,
  33.                eot = 0x04,
  34.                ack = 0x06,
  35.                nak = 0x15,
  36.                can = 0x18,
  37.                crcinit = 'C',
  38.                cksum;
  39.  
  40. static  int    debug,
  41.                crc;
  42.  
  43. int   kleenex(),
  44.       onalarm(); 
  45.  
  46. unsigned       crcsum;
  47.  
  48. xget(fp, opts)
  49. FILE     *fp;
  50. int      opts;
  51. {
  52.       char  buf[BSIZE], 
  53.             b = 1,
  54.             inch,
  55.             crchi;
  56.       int   iput = BSIZE; 
  57.       register      i; 
  58.  
  59.       debug = (opts & DEBUG);
  60.       crc = (opts & CRC);
  61.       signal(SIGALRM, onalarm);
  62. #ifdef CU
  63.       signal(SIGINT, kleenex);
  64. #else
  65.       sleep(10);
  66. #endif
  67.       (crc) ? TX(crcinit) : TX(nak);
  68.       for ever {
  69.          if NOREAD(10, inch) {
  70.                err("Timeout during SOH");
  71.                cksend(crc ? crcinit : nak) ;
  72.                continue;
  73.          }
  74.          if (inch == eot) 
  75.                break;
  76.          if (inch == can) {
  77.                err("CAN block %u", b);
  78.                kleenex(-1);
  79.          }
  80.          if (inch != soh) {
  81.                err("Bad SOH block %u: %#x", b, (inch & 0xff));
  82.                cksend(nak);
  83.                continue;
  84.          }
  85.          if NOREAD(2, inch) {
  86.                err("Timeout block %u during blocknum", b);
  87.                cksend(nak);
  88.                continue;
  89.          }
  90.          if ((inch & 0xff) != b) {
  91.                err("Expected blocknum %u, got %u", b, (inch & 0xff));
  92.                cksend(nak);
  93.                continue;
  94.          }
  95.          if NOREAD(2, inch) {
  96.                err("Timeout block %u during ~blocknum", b);
  97.                cksend(nak);
  98.                continue;
  99.          }
  100.          if ((inch & 0xff) != (~b & 0xff)) {
  101.                err("Expected ~blocknum %u, got %u",
  102.                        (~b & 0xff), (inch & 0xff));
  103.                cksend(nak);
  104.                continue;
  105.          }
  106. /* Read in 128 byte block without taking time for checksums or crc. */
  107.          for (i = 0; i < BSIZE; i++)
  108.                if NOREAD(2, buf[i]) 
  109.                      break;
  110.          if (i < BSIZE) {
  111.                err("Timeout data recv, char #%d", i);
  112.                cksend(nak);
  113.                continue;
  114.          }
  115.          if (crc) {
  116.                if NOREAD(2, crchi) {
  117.                      err("Timeout crc hibyte");
  118.                      cksend(nak);
  119.                      continue;
  120.                }
  121.                crchi &= 0xff;
  122.          }
  123.              if NOREAD(2, inch) {
  124.                err("Timeout %s", (crc) ? "crc lobyte" : "checksum");
  125.                cksend(nak);
  126.                continue;
  127.          }
  128. /* Now, when we have the whole packet, do the checksum or crc. */
  129.          for (cksum = 0, crcsum = 0, i = 0; i < BSIZE; i++) 
  130.                upsum(buf[i]);
  131.          if (crc) {
  132.                upsum(0);        /* needed for crcsum */
  133.                upsum(0);
  134.                if ((inch & 0xff) + (crchi << 8) != crcsum) {
  135.                      err("Expected crc %u, got %u", 
  136.                            crcsum, (inch & 0xff) + (crchi << 8));
  137.                      cksend(nak);
  138.                      continue;
  139.                }
  140.          }
  141.          else {
  142.                cksum %= 256;
  143.                if (cksum != (inch & 0xff)) {
  144.                      err("Expected checksum %u, got %u",
  145.                            cksum, (inch & 0xff));
  146.                      cksend(nak);
  147.                      continue;
  148.                }
  149.          }
  150.          TX(ack);
  151. #ifdef CU
  152.          putc('.', stderr);
  153. #endif
  154.          if (opts & LF) 
  155.                for (i=0, iput=0; i < BSIZE; i++) {
  156.                      if (buf[i] == 0x1a)  /* old ms-dos eof */
  157.                            break;
  158.                      if (buf[i] != '\r')
  159.                            buf[iput++] = buf[i];
  160.                }
  161.          fwrite(buf, iput, 1, fp);
  162.          b++;
  163.          b %= 256;
  164.    }
  165.    TX(ack);
  166.    kleenex(0);
  167. }
  168.  
  169. xput(fp, opts)
  170. FILE     *fp;
  171. int      opts;
  172. {
  173.    register      i; 
  174.    char    buf[BSIZE],
  175.            b = 1,
  176.            cb,
  177.            crclo,
  178.            inch;
  179.    int     cread;
  180.  
  181. #ifdef CU
  182.    signal(SIGINT, kleenex);
  183. #endif
  184.    signal(SIGALRM, onalarm);
  185.    debug = (opts & DEBUG);
  186.    rchar(60, &cb);
  187.    if (cb == crcinit)
  188.          crc = 1;
  189.    else if (cb == nak)
  190.          crc = 0;
  191.    else  {
  192.          err("No startup %s", (crc) ? "'C'" : "NAK");
  193.          kleenex(-1);
  194.    }
  195.    cread = fillbuf(fp, buf, (opts & LF));
  196.    while (cread) {
  197.          for (i = cread; i < BSIZE; i++) 
  198.                buf[i] = 0;
  199.          TX(soh);
  200.          TX(b);
  201.          cb = (~b & 0xff);
  202.          TX(cb);
  203.          write(WFD, buf, BSIZE);
  204.          for (cksum = 0, crcsum = 0, i = 0; i < BSIZE; i++) 
  205.                upsum (buf[i]);
  206.          if (crc) {
  207.                upsum(0);        /* needed for crcsum */
  208.                upsum(0);
  209.                crclo = crcsum;
  210.                cb = (crcsum >> 8);
  211.                TX(cb);
  212.                TX(crclo);
  213.          }
  214.          else {
  215.                cksum %= 256;
  216.                TX(cksum);
  217.          }
  218.          if NOREAD(15, inch) {
  219.                err("Timeout after block %u", b);
  220.                continue;
  221.          }
  222.          if (inch == can) {
  223.                err("CAN after block %u", b);
  224.                kleenex(-1);
  225.          }
  226.          if (inch != ack) {
  227.                err("Non-ACK after block %u: %#x", b, inch);
  228.                continue;
  229.          }
  230. #ifdef CU
  231.          putc('.', stderr);
  232. #else
  233.          if (debug) 
  234.                fprintf(errf, "Validated block %u\n", b);
  235. #endif
  236.          cread = fillbuf(fp, buf, (opts & LF));
  237.          b++;
  238.          b %= 256;
  239.       }
  240.       for ever {
  241.             TX(eot);
  242.             if NOREAD(15, inch) {
  243.                   err("Timeout during EOT");
  244.                   continue;
  245.             }
  246.             if (inch == can) {
  247.                   err("CAN during EOT");
  248.                   kleenex(-1);
  249.             }
  250.             if (inch != ack) {
  251.                   err("Non-ACK during EOT: %#x", inch);
  252.                   continue;
  253.             }
  254.             break;
  255.       }
  256.       kleenex(0);
  257. }
  258.  
  259. fillbuf(fp, buf, lf)
  260. FILE *fp;
  261. char *buf;
  262. int lf;
  263. {
  264.       int      i = 0, c; 
  265.       static   int      cr_held; 
  266.  
  267.       if (cr_held) {
  268.             buf[i] = '\n';
  269.             i++;
  270.             cr_held--;
  271.       }
  272.       for (; i < BSIZE; i++) {
  273.             if ((c = getc(fp)) == EOF)
  274.                   break;
  275.             if (c == '\n' && lf) {
  276.                   buf[i] = '\r';
  277.                   if (i == 127) {
  278.                         cr_held++;
  279.                         return BSIZE;
  280.                   }
  281.                   buf[i+1] = '\n';
  282.                   i++;
  283.             }
  284.             else
  285.                   buf[i] = c;
  286.       }
  287.       return i;
  288. }
  289.  
  290. upsum(c)
  291. char      c;
  292. {
  293.       register  unsigned  shift;
  294.       register  unsigned  flag;
  295.  
  296.       if (crc)
  297.             for (shift = 0x80; shift; shift >>= 1)  {
  298.                   flag = (crcsum & 0x8000);
  299.                   crcsum <<= 1;
  300.                   crcsum |= ((shift & c) ? 1 : 0);
  301.                   if (flag)
  302.                         crcsum ^= 0x1021;
  303.             }
  304.       else
  305.             cksum += c;
  306. }
  307.  
  308. /* Timeout in rchar() works by deliberately interrupting the read()
  309.  * system call.  errno=EINTR, so no reason for a perror() autopsy. */
  310. rchar(timeout, cp)
  311. unsigned timeout;
  312. char *cp;
  313. {
  314.    int      c; 
  315.  
  316.    alarm(timeout);
  317.    if ((c = read(RFD, cp, 1)) == -1)
  318.          return -1;
  319.    alarm(0);
  320.    return c;
  321. }
  322.  
  323. onalarm()
  324. {
  325.    signal(SIGALRM, onalarm);
  326. }
  327.  
  328. kleenex(sig)
  329. int sig;
  330. {
  331. #ifdef CU
  332.    if (sig > 0)
  333.          cksend(can);
  334.    else 
  335.          fprintf(stderr, "\r\nFile transfer %s.",
  336.                (sig) ? "cancelled" : "complete");
  337.    fprintf(stderr, "\r\n");
  338. #else
  339.    printf("File transfer %s.\r\n", (sig) ? "cancelled" : "complete");
  340.    resetline();
  341. #endif
  342.    exit(sig);
  343. }
  344.  
  345. cksend(ch)
  346. char ch;
  347. {
  348.    int j;
  349.    char cp;
  350.  
  351.    do {
  352.          j = rchar(2, &cp);
  353.    } while (j != -1);
  354.    TX(ch);
  355. }
  356.  
  357. /* VARARGS1 */
  358. err(s, i, j)
  359. char     *s;
  360. int      i, j;
  361. {
  362.       if (debug) {
  363.             fprintf(errf, s, i, j);
  364. #ifndef CU
  365.             fprintf(errf, "\n");
  366.       }
  367. #else
  368.             fprintf(errf, "\r\n");
  369.       }
  370.       else
  371.             putc('%', stderr);
  372. #endif
  373. }
  374.